using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

namespace Woz
{
    /// <summary>
    /// defines the run screens navigation bar that is found in the run screens mode
    /// </summary>
    public partial class RunScreensNavBar : UserControl
    {
        /// <summary>
        /// default constructor
        /// </summary>
        public RunScreensNavBar()
        {
            InitializeComponent();

            // create the previous screens stack
            this.mPrevScreens = new Stack<Woz.Screen>();

            // create the context menu
            this.mNextScreensMenu = new ContextMenuStrip();

            // initialize the ordered screens list
            this.mOrderedScreens = new List<Woz.Screen>();

            // initialize the variables needed for previewing the next screen
            this.mThumbnailPreviewOutlineImage = global::Woz.Properties.resources.thumbnail_preview_outline;
            this.mThumbnailDrawingRectangle = new Rectangle();
            this.mThumbnailDrawingRectangle.Location = new Point((this.Width / 2) - (this.mThumbnailPreviewOutlineImage.Width / 2), this.Height - this.mButtonStop.Height - this.mThumbnailPreviewOutlineImage.Height - 10);
            this.mThumbnailDrawingRectangle.Size = this.mThumbnailPreviewOutlineImage.Size;

            this.mNextScreensMenu.Closed += new ToolStripDropDownClosedEventHandler(this.cNextScreensMenuClosed);
        }

        /// <summary>
        /// determines if using linear transitions or not and builds the ordered screen list accordingly
        /// </summary>
        public void InitializeScreens()
        {
            if (Woz.DynamicVariables.Instance.UsingCustomTransitions)
            {
                foreach (Woz.Screen screen in Woz.ScreenManager.Instance.Screens)
                {
                    if (!screen.Hidden && (screen.TransitionsThumbnail.TabIndex > 0))
                    {
                        Woz.ScreenManager.Instance.SelectedScreen = screen;
                        break;
                    }
                }
            }
            else
            {
                this.mOrderedScreens.Clear();
                this.mScreenPosition = 0;
                foreach (Woz.Screen screen in Woz.ScreenManager.Instance.Screens)
                {
                    if (!screen.Hidden)
                    {
                        this.mOrderedScreens.Add(screen);
                    }
                }

                this.mOrderedScreens.Sort(this.CompareScreensLinear);
                Woz.ScreenManager.Instance.SelectedScreen = this.mOrderedScreens[this.mScreenPosition];
            }
            this.mPrevScreens.Clear();
            this.UpdateNavButtonsEnableness();
        }

        /// <summary>
        /// predicate well use to sort the screens
        /// </summary>
        /// <param name="pFirstScreen">first screen</param>
        /// <param name="pSecondScreen">second screen</param>
        /// <returns>positive if tab index of first is greater than the second</returns>
        private int CompareScreensLinear(Woz.Screen pFirstScreen, Woz.Screen pSecondScreen)
        {
            return (pFirstScreen.SliderThumbnail.TabIndex - pSecondScreen.SliderThumbnail.TabIndex);
        }

        /// <summary>
        /// updates the enabledness of all the buttons we have
        /// </summary>
        private void UpdateNavButtonsEnableness()
        {
            this.mButtonPrev.Enabled = (this.mPrevScreens.Count > 0);
            if (Woz.DynamicVariables.Instance.UsingCustomTransitions)
            {
                this.mButtonNext.Enabled = (Woz.ScreenManager.Instance.SelectedScreen.NextScreens.Length > 0);
            }
            else
            {
                this.mButtonNext.Enabled = (this.mScreenPosition < this.mOrderedScreens.Count - 1);
            }

            // throw the focus off of any buttons
            this.mLabelFocusTaker.Focus();
        }

        /// <summary>
        /// gets called with the previous button gets clicked
        /// </summary>
        /// <param name="pSender">previous button</param>
        /// <param name="pEventArgs">empty event args</param>
        private void cPreviousButtonClicked(object pSender, EventArgs pEventArgs)
        {
            // go to the previous screen
            Woz.Screen prevScreen = this.mPrevScreens.Pop();

            Woz.ScreenManager.Instance.SelectedScreen = prevScreen;
            --this.mScreenPosition;

            // update the nav buttons
            this.UpdateNavButtonsEnableness();
        }

        /// <summary>
        /// gets called with the stop button gets clicked
        /// </summary>
        /// <param name="pSender">stop button</param>
        /// <param name="pEventArgs">empty event args</param>
        private void cStopButtonClicked(object pSender, EventArgs pEventArgs)
        {
            // switch back to old mode
            Woz.MainForm.Instance.ToggleRunMode();
        }

        /// <summary>
        /// gets called with the next button gets clicked
        /// </summary>
        /// <param name="pSender">next button</param>
        /// <param name="pEventArgs">empty event args</param>
        private void cNextButtonClicked(object pSender, EventArgs pEventArgs)
        {
            if (Woz.DynamicVariables.Instance.UsingCustomTransitions)
            {
                // get a list of the next screens so we dont have to keep looking up
                Woz.Screen[] nextScreens = Woz.ScreenManager.Instance.SelectedScreen.NextScreens;

                // first check to see if there are more than one next screens
                if (nextScreens.Length > 1)
                {
                    // clear the old stuff in the menu items
                    this.mNextScreensMenu.Items.Clear();

                    // create the new menu items
                    foreach (Woz.Screen screen in nextScreens)
                    {
                        // create the menu item
                        ToolStripItem item = new ToolStripMenuItem(screen.Name);

                        // add a callback to the mouse over event on this item
                        item.MouseEnter += new EventHandler(cNextScreenMenuItemMouseOvered);

                        // attach the screen
                        item.Tag = (object)screen;

                        // add it to the context menu
                        this.mNextScreensMenu.Items.Add(item);
                    }

                    // save the current screen in the screen manager
                    this.mScreenBeforeNextScreensMenuPoppedUp = Woz.ScreenManager.Instance.SelectedScreen;

                    // now show the menu
                    this.mNextScreensMenu.Show(this.mButtonNext, new Point(0, this.mButtonNext.Height));

                    // invalidate ourselves to get rid of the preview thumbnail that got drawn
                    //this.Invalidate(this.mThumbnailDrawingRectangle);
                }

                else if (nextScreens.Length == 1)
                {
                    // save the last screen
                    this.mPrevScreens.Push(Woz.ScreenManager.Instance.SelectedScreen);

                    // go to the new screen
                    Woz.ScreenManager.Instance.SelectedScreen = nextScreens[0];
                }
            }
            else
            {
                // go to the next screen (sequentially)
                this.mPrevScreens.Push(Woz.ScreenManager.Instance.SelectedScreen);
                Woz.ScreenManager.Instance.SelectedScreen = this.mOrderedScreens[++this.mScreenPosition];
            }

            // update the nav buttons
            this.UpdateNavButtonsEnableness();
        }

        /// <summary>
        /// called when a menu item from the next screens menu gets mouse overed
        /// </summary>
        /// <param name="pSender">menu item that got mouse overed</param>
        /// <param name="pEventArgs">empty event args</param>
        void cNextScreenMenuItemMouseOvered(object pSender, EventArgs pEventArgs)
        {
            // retrieve the screen from this menu item
            Woz.Screen screen = ((ToolStripMenuItem)pSender).Tag as Woz.Screen;

            Woz.ScreenManager.Instance.SelectedScreen = screen;

            // were going to draw a thumbnail of this screen to ourselves
            /*using (Graphics graphics = this.CreateGraphics())
            {
                // calculate the position where we will rener the actual image
                Point actualImageLocation = this.mThumbnailDrawingRectangle.Location;
                actualImageLocation.Offset(4, 4);

                // draw the outline of the thumbnail first then the thumbnail on top of it
                graphics.DrawImageUnscaled(this.mThumbnailPreviewOutlineImage, this.mThumbnailDrawingRectangle);
                graphics.DrawImageUnscaled(screen.ThumbnailImage, actualImageLocation);
            }*/
        }

        void cNextScreensMenuClosed(object pSender, ToolStripDropDownClosedEventArgs pEventArgs)
        {
            if (pEventArgs.CloseReason == ToolStripDropDownCloseReason.ItemClicked)
            {
                // save the last screen
                this.mPrevScreens.Push(this.mScreenBeforeNextScreensMenuPoppedUp);

                // update the nav buttons
                this.UpdateNavButtonsEnableness();
            }

            else
            {
                Woz.ScreenManager.Instance.SelectedScreen = this.mScreenBeforeNextScreensMenuPoppedUp;
            }
        }

        /// <summary>
        /// the current ordered screen position
        /// </summary>
        private int mScreenPosition;

        /// <summary>
        /// linearly ordered screens
        /// </summary>
        private List<Woz.Screen> mOrderedScreens;

        /// <summary>
        /// a stack of the previous screens
        /// </summary>
        private Stack<Woz.Screen> mPrevScreens;

        /// <summary>
        /// the context menu that shows up for the next screens
        /// </summary>
        private ContextMenuStrip mNextScreensMenu;

        /// <summary>
        /// image to serve as an outline and border when previewing thumbnails
        /// </summary>
        private Image mThumbnailPreviewOutlineImage;

        /// <summary>
        /// rectangle where the thumbnail will be rendered
        /// </summary>
        private Rectangle mThumbnailDrawingRectangle;

        private Woz.Screen mScreenBeforeNextScreensMenuPoppedUp;
    }
}
